#pragma once

#include <vector>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>

#include "AEWorker.hpp"
#include "AETask.hpp"

BEGIN_ARETE_NAMESPACE(thread)

class AETaskManager
	: public Ogre::Singleton<AETaskManager>
{
public:
	AETaskManager(void);
	~AETaskManager(void);

	void initialize(const size_t&);

	template<class T, class R>
	std::future<T> enqueue(R);

private:
	friend class AEWorker;

	std::vector<std::thread> m_workers;
	std::deque<AETask> m_tasks;

	std::mutex m_mutex;
	std::condition_variable m_condition;
	bool m_stop;
};

template<class T, class R>
std::future<T> AETaskManager::enqueue(R _r)
{
	std::packaged_task<T()> task(_r);
	std::future<T> res = task.get_future();
	{
		std::unique_lock<std::mutex> lock(m_mutex);
		m_tasks.push_back(AETask(std::move(task)));
	}

	m_condition.notify_one();
	return res;
}

END_ARETE_NAMESPACE